//
//  RaknetHelper.cpp
//  boxer
//
//  Created by Wu Wang on 11-12-14.
//  Copyright (c) 2011年 __MyCompanyName__. All rights reserved.
//

#include "RaknetHelper.h"

#ifdef GAME_USERAKNET

#include "cocos2d.h"
#include <ctime>

using namespace RakNet;

CRaknetHelper *g_raknet = NULL;

pthread_t CRaknetHelper::m_pid = NULL;

CRaknetHelper* CRaknetHelper::GetInstance()
{
    if(NULL == g_raknet)
    {
        g_raknet = new CRaknetHelper;
    }
    
    return g_raknet;

}
CRaknetHelper::CRaknetHelper()
: m_bConnected(false)
{
    
}

CRaknetHelper::~CRaknetHelper()
{
	StopReceiveThread();
}

bool CRaknetHelper::InitState(const char *szID, int length, CNetworkDelegate *delegate)
{
    m_pDelegate = delegate;
    
    if(length > ID_MAX_LENGTH)
    {
        return false;
    }
    
    strcpy(m_userID, szID);
    
    return true;
}

bool CRaknetHelper::ConnectServer(const char *szUser, CClientDelegate *pDelegate)
{
    SocketDescriptor u;
    m_pRakPeer = RakPeerInterface::GetInstance();
    m_pRakPeer->Startup(1, &u, 1);
    m_pRakPeer->Connect("192.168.2.102",13140, "lanfei20111206", strlen("lanfei20111206")+1);
    
    BeginReceiveThread();
    return true;
}

bool CRaknetHelper::ConnectRandomRoom()
{
    BitStream rakStream;
    rakStream.Write((MessageID)ID_GAME_ROOMING);
    rakStream.Write((MessageID)ID_ROOM_RANDOM);
    
    m_pRakPeer->Send(&rakStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, m_serverGuid, false);
    
    return true;
}

bool CRaknetHelper::SendClientCommand(const ClientPacket &packet)
{
    BitStream rakStream;
    rakStream.Write((MessageID)ID_GAME_FIGHTING);
    rakStream.Write((MessageID)ID_FIGHT_TEST);
	rakStream.Write((MessageID)PACKET_CLIENT);
    rakStream.Write((char *)&packet, sizeof(packet));
    
    m_pRakPeer->Send(&rakStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, m_serverGuid, false);
    
    return true;
}

bool CRaknetHelper::SendServerInfo(const GameInfo &info)
{
    BitStream rakStream;
    rakStream.Write((MessageID)ID_GAME_FIGHTING);
    rakStream.Write((MessageID)ID_FIGHT_TEST);
	rakStream.Write((MessageID)PACKET_SREVER);
    rakStream.Write((char *)&info, sizeof(info));
    
    m_pRakPeer->Send(&rakStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, m_serverGuid, false);
    return true;
}

void CRaknetHelper::DelayTest()
{
    timeval time;
    gettimeofday(&time	, NULL);
    long millions = time.tv_sec * 1000 + time.tv_usec / 1000;
    
    static long lastTime = millions;
    
    if(millions - lastTime < 5000)
    {
        return;
    }
    
    lastTime = millions;
    
    BitStream rakStream;
    rakStream.Write((MessageID)ID_GAME_FIGHTING);
    rakStream.Write((MessageID)ID_FIGHT_TEST);
    rakStream.Write((MessageID)PACKET_DELAYTEST);
    rakStream.Write(millions);
    m_delay = millions;
    
    m_pRakPeer->Send(&rakStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, m_serverGuid, false);    
}

bool CRaknetHelper::BeginReceiveThread()
{
    if(NULL != m_pid)
    {
        StopReceiveThread();
    }
    pthread_create(&m_pid, NULL, ThreadReceiveData, g_raknet);
    return true;
}
bool CRaknetHelper::StopReceiveThread()
{
	if(NULL == m_pid)
	{
		return false;
	}

    pthread_cancel(m_pid);
    
	m_pid = NULL;

	return true;
}

void *CRaknetHelper::ThreadReceiveData(void *arg)
{
	CRaknetHelper *pRaknet = (CRaknetHelper *)arg;
    
	while (true) 
	{
		pRaknet->ReceiveData();
	}

	return NULL;
}

void CRaknetHelper::ReceiveData()
{
    Packet *pPacket;
    BitStream rakStream;
    
    for(pPacket = m_pRakPeer->Receive(); pPacket != NULL;pPacket = m_pRakPeer->Receive())
    {
    
        CCLOG("rannet::%d", pPacket->data[0]);
        rakStream.Reset();
        switch (pPacket->data[0]) 
        {
            case ID_CONNECTION_REQUEST_ACCEPTED:
                m_serverGuid = pPacket->guid;
                rakStream.Write((MessageID)ID_GAME_LOGING);
                rakStream.Write((MessageID)ID_LOGING_LOGING);
                rakStream.Write(m_userID, ID_MAX_LENGTH);
                m_pRakPeer->Send(&rakStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, m_serverGuid, false);
                break;
                
            case ID_CONNECTION_ATTEMPT_FAILED:
                
                m_pDelegate->connectServerFailed();
                break;
                
            case ID_CONNECTION_LOST:
                m_pDelegate->connectLost();
                break;
                
            case ID_GAME_LOGING:
                if(pPacket->data[1] == ID_LOGING_LOGING_SUCCESS)
                {
                    m_pDelegate->connectServerSuccessed();
                }
                else if(pPacket->data[1] == ID_LOGING_CREATENAME)
                {
                    rakStream.Write((MessageID)ID_GAME_LOGING);
                    rakStream.Write((MessageID)ID_LOGING_CREATENAME);
                    rakStream.Write(m_userID, ID_MAX_LENGTH);
                    m_pRakPeer->Send(&rakStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, m_serverGuid, false);

                }
                break;
                
            case ID_GAME_ROOMING:
                if(pPacket->data[1]== ID_ROOM_SUCCESS)
                {
                    BoxerInfo info;
                    
                    rakStream.WriteAlignedBytes(pPacket->data, pPacket->length);
                    rakStream.IgnoreBytes(2);
                    unsigned char role;
                    rakStream.Read(role);
                    
                    if(ID_HOST == role)
                    {
                        m_bHost = true;
                    }
                    else
                    {
                        m_bHost = false;
                    }
                    
                    rakStream.Read((char *)&info, sizeof(info));
                    
                    m_pDelegate->opponentFound(info);
                }
                break;
                
            case ID_GAME_FIGHTING:
                if(pPacket->data[1] == ID_FIGHT_TEST)
                {
					if(pPacket->data[2] == PACKET_CLIENT)
					{
						rakStream.WriteAlignedBytes(pPacket->data, pPacket->length);
						rakStream.IgnoreBytes(3);
						ClientPacket p;
						rakStream.Read((char *)&p.m_command, sizeof(p.m_command));
						m_pDelegate->receiveCommand(p);
					}
					else if(pPacket->data[2] == PACKET_SREVER)
					{
						rakStream.WriteAlignedBytes(pPacket->data, pPacket->length);
						rakStream.IgnoreBytes(3);
						GameInfo info;
						rakStream.Read((char *)&info, sizeof(info));
						m_pDelegate->receiveServerInfo(info);
					}
                    else if(pPacket->data[2] == PACKET_DELAYTEST)
                    {
                        rakStream.WriteAlignedBytes(pPacket->data, pPacket->length);
                        rakStream.IgnoreBytes(3);
                        long lastTime;
                        rakStream.Read(lastTime);
                        timeval time;
                        gettimeofday(&time	, NULL);
                        long millions = time.tv_sec * 1000 + time.tv_usec / 1000;
                        CCLOG("curDelay %ld", millions - lastTime);
                    }
                }
                
                break;
    
            default:
                break;
        }
        
        m_pRakPeer->DeallocatePacket(pPacket);
    }
}

pthread_mutex_t CAutoMutex::m_hMutex;
void CAutoMutex::Init()
{
    int error = pthread_mutex_init(&m_hMutex, 0);
	(void) error;
	RakAssert(error==0);
}

void CAutoMutex::Destroy()
{
    pthread_mutex_destroy(&m_hMutex);
}
CAutoMutex::CAutoMutex()
{
    /*
	int error = pthread_mutex_lock(&m_hMutex);
	(void) error;
	RakAssert(error==0);
     */
}

CAutoMutex::~CAutoMutex()
{
    /*
	int error = pthread_mutex_unlock(&m_hMutex);
	(void) error;
	RakAssert(error==0);
     */
}

#endif